/*$T romlist.c GC 1.136 03/09/02 17:32:23 */


/*$6
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
    Routines for populating and sorting the romlist browser
 +++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
 */


/*
 * 1964 Copyright (C) 1999-2004 Joel Middendorf, <schibo@emulation64.com> This
 * program is free software; you can redistribute it and/or modify it under the
 * terms of the GNU General Public License as published by the Free Software
 * Foundation; either version 2 of the License, or (at your option) any later
 * version. This program is distributed in the hope that it will be useful, but
 * WITHOUT ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for more
 * details. You should have received a copy of the GNU General Public License
 * along with this program; if not, write to the Free Software Foundation, Inc.,
 * 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. To contact the
 * authors: email: schibo@emulation64.com, rice1964@yahoo.com
 */
#include "stdafx.h"

/* Global variabls */
ROMLIST_ENTRY	*romlist[MAX_ROMLIST];
static char		savedrompath[_MAX_PATH];

ROMLIST_STATUS	rlstatus;

POINT			savedPosition;
RECT			savedViewRect;
RECT			savedItemRect;

void __cdecl RomListGetGoodRomNameToDisplay(	char	*buf,  int		index );

ColumnType romListColumns[] =
{
	{ROMLIST_COL_GAMENAME,	"ROM Name", 			0,	TRUE,	180,	0},	//The first column is always the filename, and always enabled
	{ROMLIST_COL_COUNTRY,	"Country",				1,	TRUE,	50,		0},
	{ROMLIST_COL_SIZE,		"Size",					2,	TRUE,	50,		0},
	{ROMLIST_COL_STATUS,	"Compatibility Status",	3,	TRUE,	360,	0},
	{ROMLIST_COL_GAMESAVE,	"Save Type",			4,	FALSE,	30,		0},
	{ROMLIST_COL_CICCHIP,	"CIC Chip",				5,	FALSE,	30,		0},
	{ROMLIST_COL_CRC1,		"CRC1",					6,	FALSE,	30,		0},
	{ROMLIST_COL_CRC2,		"CRC2",					7,	FALSE,	30,		0},
	{ROMLIST_COL_PLAYERS,	"Players",				8,	FALSE,	30,		0},
};

const int numberOfRomListColumns = sizeof(romListColumns)/sizeof(ColumnType);
ColumnID GetColumnIDByName(char *name);
ColumnID GetColumnIDByPos(int pos);
void InsertColumnsIntoTreeView(HWND hwndTV);

void TranslateRomPopupMenu(HMENU hMenu);
void TranslateColumnPopupMenu1(HMENU hMenu);
void TranslateColumnPopupMenu2(HMENU hMenu);
void TranslatePopupMenu3(HMENU hMenu);

/*
 =======================================================================================================================
    Functions
 =======================================================================================================================
 */
extern BOOL WindowMsgLoop ();

BOOL __cdecl RomListReadDirectory(const char *spath, BOOL usecached)
{
	char			romfilename[_MAX_PATH];
	char			drive[_MAX_DRIVE], dir[_MAX_DIR];
	char			filename[_MAX_FNAME], ext[_MAX_EXT];
	char			searchpath[_MAX_PATH];
	char			path[_MAX_PATH];
	HANDLE			findfirst;
	WIN32_FIND_DATA libaa;
	long			filesize;
	INI_ENTRY		entry;

	char			cachedListFilename[256];
	FILE			*fp;

	entry.Code_Check = CODE_CHECK_DEFAULT;
	entry.Comments[0] = '\0';
	entry.Alt_Title[0] = '\0';
	entry.countrycode = 0;
	entry.crc1 = 0;
	entry.crc2 = 0;
	entry.Emulator = DEFAULT_EMULATORTYPE;
	entry.Game_Name[0] = '\0';
	entry.Max_FPS = 0;
	entry.RDRAM_Size = 0;
	entry.Save_Type = DEFAULT_SAVETYPE;
	entry.Use_TLB = 0;
	entry.Eeprom_size = 0;
	entry.Counter_Factor = 0;
	entry.Use_Register_Caching = 0;
	entry.FPU_Hack = 0;
	entry.timing_Control = DELAY_DMA;
	entry.Link_4KB_Blocks = 0;
	entry.Assume_32bit = 0;
	entry.Use_HLE = 0;
	entry.Advanced_Block_Analysis = 0;
	entry.RSP_RDP_Timing = 0;
	entry.frame_buffer_rw = 0;
	entry.numberOfPlayers = 1;
	entry.videoPluginName[0] = '\0';
	entry.audioPluginName[0] = '\0';
	entry.inputPluginName[0] = '\0';
	entry.rspPluginName[0] = '\0';
	entry.iconFilename[0] = '\0';

	strcpy(directories.last_rom_directory, spath);
	REGISTRY_WriteStringByName("LastROMDirectory", directories.last_rom_directory);
	
	strcpy(cachedListFilename,directories.main_directory);
	strcat(cachedListFilename,"\\RomCache.dat");

	if( usecached )
	{
		fp = fopen(cachedListFilename,"rt");
	}
	else
	{
		fp = NULL;
	}

	if( fp )
	{
		// File exists
		char line[512];
		int namelen;
		int ini_entries_index;

		fgets(line,511,fp);
		line[strlen(line)-1]=0;	// chop the '\a'
		if( stricmp(line+2,spath) != 0 )
		{
			fclose(fp);
			goto readDir;
		}

		while(fgets(line,511,fp))
		{
			line[strlen(line)-1]=0;	// chop the '\a'
			sscanf(line,"0x%08X,0x%08X,0x%02x,0x%08x,0x%02x",&(entry.crc1),&(entry.crc2),&(entry.countrycode),&filesize,&namelen);
			strncpy(entry.Game_Name,line+43,namelen);
			entry.Game_Name[namelen]=0;
			strcpy(romfilename,line+44+namelen);
			// Add the header information to our romlist
			if((ini_entries_index = FindIniEntry2(&entry)) >= 0 || (ini_entries_index = AddIniEntry(&entry)) >= 0)
			{
				// Add the romlist
				RomListAddEntry(&entry, romfilename, filesize);
			}
		}

		fclose(fp);
	}
	else
	{
readDir:
		fp = fopen(cachedListFilename,"wt");
		if( fp )
			fprintf(fp,"##%s\n", spath);


		strcpy(savedrompath, spath);
		strcpy(path, spath);
		if(path[strlen(path) - 1] != '\\') strcat(path, "\\");

		strcpy(searchpath, path);
		strcat(searchpath, "*.*");

		findfirst = FindFirstFile(searchpath, &libaa);
		if(findfirst == INVALID_HANDLE_VALUE)
		{
			/* No file in the rom directory */
			return(FALSE);
		}

		SetStatusBarText(0, TranslateStringByString("Updating ROM browser..."));
		do
		{
			WindowMsgLoop();

			strcpy(romfilename, path);
			strcat(romfilename, libaa.cFileName);
			_splitpath(romfilename, drive, dir, filename, ext);
			_strlwr(ext);	/* Convert file extension to lower case */

			/*
			* DisplayError("Fullname=%s, drive=%s, dir=%s, filename=%s, ext=%s", romfilename,
			* drive, dir, filename, ext);
			*/
			if
			(
				stricmp(ext, ".rom") == 0
			||	stricmp(ext, ".v64") == 0
			||	stricmp(ext, ".z64") == 0
			||	stricmp(ext, ".usa") == 0
			||	stricmp(ext, ".n64") == 0
			||	stricmp(ext, ".bin") == 0
			||	stricmp(ext, ".zip") == 0
			||	stricmp(ext, ".j64") == 0
			||	stricmp(ext, ".pal") == 0
			)
			{
				if(strcmp(ext, ".zip") == 0)
				{
					/* Open and read this zip file */
					if((filesize = ReadZippedRomHeader(romfilename, &entry)) == 0)
					{
						/* This is not a ROM zip file, skipped it */
						continue;
					}
				}
				else
				{
					/* Open and read this rom file */
					if((filesize = ReadRomHeader(romfilename, &entry)) == 0)
					{
						/* This is not a ROM file, skipped it */
						continue;
					}
				}

				if( fp )
				{
					fprintf(fp,"0x%08X,0x%08X,0x%02x,0x%08x,0x%02x,%s,%s\n",entry.crc1,entry.crc2,entry.countrycode,filesize,strlen(entry.Game_Name),entry.Game_Name,romfilename);
				}

				/* Add the header information to our romlist */
				{
					/*~~~~~~~~~~~~~~~~~~*/
					int ini_entries_index;
					/*~~~~~~~~~~~~~~~~~~*/

					if((ini_entries_index = FindIniEntry2(&entry)) >= 0 || (ini_entries_index = AddIniEntry(&entry)) >= 0)
					{
						/* Add the romlist */
						strcat(filename, ext);
						RomListAddEntry(&entry, romfilename, filesize);
					}
					else
					{
						/*
						* Cannot add to ini_entries list for some reason ?						* Skipped
						*/
						continue;
					}
				}
			}
			else
			{
				continue;	/* Skip this file */
			}
		} while(FindNextFile(findfirst, &libaa));

		if( fp )	
			fclose(fp);
	}

	rlstatus.selected_rom_index = 0;
	NewRomList_Sort();
	return TRUE;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl ClearRomList( void )
{
	/*~~~~~~~~~~~~~~*/
	register int	i;
	/*~~~~~~~~~~~~~~*/

	for(i = 0; i < rlstatus.romlist_count; i++)
	{
		/* VirtualFree((void*)romlist[i], sizeof(ROMLIST_ENTRY), MEM_DECOMMIT); */
		VirtualFree((void *) romlist[i], 0, MEM_RELEASE);
		romlist[i] = NULL;
	}

	rlstatus.romlist_count = 0;
}

/*
 =======================================================================================================================
    Init the whole list, this function must be call before any other ROMLIST functions
 =======================================================================================================================
 */
void  __cdecl InitRomList( void )
{
	/*~~~~~~~~~~~~~~*/
	register int	i;
	/*~~~~~~~~~~~~~~*/

	for(i = 0; i < MAX_ROMLIST; i++) romlist[i] = NULL;
	rlstatus.romlist_count = 0;
}

/*
 =======================================================================================================================
    Return value is the index of the new entry that is added into the list
 =======================================================================================================================
 */
int _cdecl RomListAddEntry(INI_ENTRY *newentry, char *romfilename, long filesize)
{
	/*~~~~~~*/
	int index;
	/*~~~~~~*/

	if(rlstatus.romlist_count == MAX_ROMLIST)
	{
		DisplayError("Your directory contains too many roms, I cannot display it");
		return -1;
	}

	if((index = FindIniEntry2(newentry)) >= 0 || (index = AddIniEntry(newentry)) >= 0)
	{
		/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
		/*
		 * We can either locate the entry in the ini_entries list ?		 * or this is a new entry, never in the ini_entries list, but we have ?		 * successfully add it into the ini_entries list ?		 * Allocate memory for a new ROMLIST_ENTRY
		 */
		ROMLIST_ENTRY	*pnewentry = NULL;
		/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

		pnewentry = (ROMLIST_ENTRY *) VirtualAlloc(NULL, sizeof(ROMLIST_ENTRY), MEM_COMMIT, PAGE_READWRITE);
		if(pnewentry == NULL)	/* fail to allocate memory */
			return -1;

		pnewentry->pinientry = ini_entries[index];
		strcpy(pnewentry->romfilename, romfilename);
		pnewentry->size = filesize;

		/* Insert the new entry sorted */
		if(rlstatus.romlist_count == 0)
		{
			rlstatus.selected_rom_index = rlstatus.romlist_count;
			romlist[rlstatus.romlist_count++] = pnewentry;
			return rlstatus.selected_rom_index;
		}
		else
		{
			int i;

			for(i = 0; i < rlstatus.romlist_count; i++)
			{
				if(stricmp(romlist[i]->pinientry->Game_Name, pnewentry->pinientry->Game_Name) >= 0) break;
			}

			if( i<rlstatus.romlist_count )
			{
				if( //stricmp(romlist[i]->pinientry->Game_Name, pnewentry->pinientry->Game_Name) == 0 &&
					romlist[i]->pinientry->crc1 == pnewentry->pinientry->crc1 &&
					romlist[i]->pinientry->crc2 == pnewentry->pinientry->crc2 &&
					romlist[i]->pinientry->countrycode == pnewentry->pinientry->countrycode )
				{
					// It is the same entry, skip it
					return -1;
				}
			}

			rlstatus.selected_rom_index = i;
			if(rlstatus.selected_rom_index < rlstatus.romlist_count)
			{
				for(i = rlstatus.romlist_count; i > rlstatus.selected_rom_index; i--) romlist[i] = romlist[i - 1];
			}

			romlist[rlstatus.selected_rom_index] = pnewentry;
			rlstatus.romlist_count++;
			return rlstatus.selected_rom_index;
		}
	}
	else
	{
		return -1;
	}
}

extern void __cdecl RefreshRecentGameMenus(char *filename);

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListOpenRom(int index, BOOL RunThisRom)
{
	char	filename[_MAX_PATH];

	if(index >= 0 && index < rlstatus.romlist_count)
	{
		rlstatus.selected_rom_index = index;
		strcpy(filename, romlist[index]->romfilename);

		ListView_GetItemPosition(gui.hwndRomList, index, &savedPosition);
		ListView_GetViewRect(gui.hwndRomList, &savedViewRect);
		ListView_GetItemRect(gui.hwndRomList, index, &savedItemRect, LVIR_ICON);

		if(WinLoadRomStep2(filename) == TRUE)
		{
			RefreshRecentGameMenus(filename);

			/* Read hack code for this rom */
			CodeList_ReadCode((char*)rominfo.name,cheatfilename);

			EnableMenuItem(gui.hMenu1964main, ID_ROM_START, MF_ENABLED);
			EnableRadioButtons(TRUE);
			EnableMenuItem(gui.hMenu1964main, ID_ROM_PAUSE, MF_GRAYED);
			EnableMenuItem(gui.hMenu1964main, ID_FILE_ROMINFO, MF_ENABLED);
			EnableButton(ID_BUTTON_ROM_PROPERTIES, TRUE);
			EnableMenuItem(gui.hMenu1964main, ID_FILE_CHEAT, MF_ENABLED);


			if( RunThisRom || Kaillera_Is_Running == TRUE)
			{
				Play(emuoptions.auto_full_screen); /* autoplay */
			}
		}
		else
		{
			EnableButton(ID_BUTTON_OPEN_ROM, TRUE);
			EnableMenuItem(gui.hMenu1964main, ID_OPENROM, MF_ENABLED);
			EnableButton(ID_BUTTON_SETUP_PLUGINS, TRUE);
			EnableMenuItem(gui.hMenu1964main, IDM_PLUGINS, MF_ENABLED);
		}
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListSelectRom( int index )
{
	if(index >= 0 && index < rlstatus.romlist_count)
	{
		rlstatus.selected_rom_index = index;
		ListView_SetHotItem(gui.hwndRomList, index);
		ListView_SetItemState(gui.hwndRomList, index, LVIS_FOCUSED|LVIS_SELECTED, LVIS_FOCUSED|LVIS_SELECTED);
		ListView_SetSelectionMark(gui.hwndRomList, index);
		EnableMenuItem(gui.hMenu1964main, ID_FILE_ROMINFO, MF_ENABLED);
		EnableButton(ID_BUTTON_ROM_PROPERTIES, TRUE);
		EnableMenuItem(gui.hMenu1964main, ID_FILE_CHEAT, MF_ENABLED);
	}
}

int __cdecl RomListGetSelectedIndex(void)
{
	return rlstatus.selected_rom_index;
}

int GetSmallIconIndex(int index);

void __cdecl RomList_UpdateNameAndComments(int index)
{
    if(index >= 0 && index < rlstatus.romlist_count)
	{
		int col, i, size;
        LVITEM lvi;
        int iSmallIcon = GetSmallIconIndex(index);


    	/* Initialize LVITEM members that are common to all items. */
    	lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
    	lvi.state = 0;
    	lvi.stateMask = 0;
    	lvi.pszText = LPSTR_TEXTCALLBACK;	/* app. maintains text */
        lvi.iImage = iSmallIcon;

		RomListSelectRom(index);

		//Looking for the column id of the field "Compatibility Status"
		size = GetColumnIDByName("Compatibility Status");
		col = 0;
		for( i=0; i<size; i++)
		{
			if( romListColumns[i].enabled )
			{
				col++;
			}
		}
		ListView_SetItemText(gui.hwndRomList, index, col, romlist[index]->pinientry->Comments);

		lvi.iItem = index;
		lvi.iSubItem = 0;

		RomListGetGoodRomNameToDisplay(generalmessage, index);
		lvi.pszText = generalmessage;
        ListView_SetItem(gui.hwndRomList, &lvi);
	}
}
/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListRomOptions(int index)
{
    RomList_UpdateNameAndComments(index);
    CreateOptionsDialog(PSH_ROM_OPTIONS);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */

#define ROM_OPTION_SET_LISTBOX(CONTROLID, SIZE, DEFAULTVALUE, VALUE, NAMES) \
	SendDlgItemMessage \
	( \
		hDlg, \
		CONTROLID, \
		CB_RESETCONTENT, \
		0, \
		0 \
	); \
	for(i = 1; i < SIZE; i++) \
	{ \
		if(DEFAULTVALUE == i) \
		{ \
			sprintf(generalmessage, "%s (%s)", TranslateStringByString(NAMES[i]), TranslateStringByString("default")); \
			SendDlgItemMessage(hDlg, CONTROLID, CB_INSERTSTRING, i - 1, (LPARAM) (generalmessage)); \
		} \
		else \
			SendDlgItemMessage(hDlg, CONTROLID, CB_INSERTSTRING, i - 1, (LPARAM) TranslateStringByString((NAMES[i]))); \
		if(i == VALUE) SendDlgItemMessage(hDlg, CONTROLID, CB_SETCURSEL, i - 1, 0); \
	} \
	if(VALUE == 0) SendDlgItemMessage(hDlg, CONTROLID, CB_SETCURSEL, DEFAULTVALUE - 1, 0);

/*
 =======================================================================================================================
 =======================================================================================================================
 */


LRESULT APIENTRY RomInfoProc(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
	char	countryname[80];
	char	tempstr[_MAX_PATH];
	int		tvsystem;

    switch(message)
	{
	case WM_INITDIALOG:
		TranslateDialag(hDlg, "ROM_INFO");

        {
			char	drive[_MAX_DIR], dir[_MAX_DIR];
			char	fname[_MAX_FNAME], ext[_MAX_EXT];

			_splitpath(romlist[rlstatus.selected_rom_index]->romfilename, drive, dir, fname, ext);
			strcat(drive, dir);
			strcat(fname, ext);

			SetDlgItemText(hDlg, IDC_ROMOPTION_FILENAME, fname);
			SetDlgItemText(hDlg, IDC_ROMOPTION_FILELOCATION, drive);
		}

		sprintf(tempstr, "%08X", romlist[rlstatus.selected_rom_index]->pinientry->crc1);
		SetDlgItemText(hDlg, IDC_ROMOPTION_CRC1, tempstr);

		sprintf(tempstr, "%08X", romlist[rlstatus.selected_rom_index]->pinientry->crc2);
		SetDlgItemText(hDlg, IDC_ROMOPTION_CRC2, tempstr);

		CountryCodeToCountryName_and_TVSystem
		(
			romlist[rlstatus.selected_rom_index]->pinientry->countrycode,
			countryname,
			&tvsystem
		);
		sprintf(tempstr, "%s (0x%02X)", TranslateStringByString(countryname), romlist[rlstatus.selected_rom_index]->pinientry->countrycode);
		SetDlgItemText(hDlg, IDC_ROMOPTION_COUNTRYCODE, tempstr);
		SetDlgItemText(hDlg, IDC_ROMOPTION_GAMENAME, romlist[rlstatus.selected_rom_index]->pinientry->Game_Name);    
 
        return(TRUE);


    //Propertysheet handling
	case WM_NOTIFY:
		{
		LPNMHDR lpnm = (LPNMHDR) lParam;

        switch (lpnm->code)
            {
			case PSN_APPLY:
				SendMessage(hDlg, WM_COMMAND, IDOK, lParam);
                EndDialog(lpnm->hwndFrom, TRUE);
				break;

            case PSN_RESET :
                //Handle a Cancel button click, if necessary
                EndDialog(lpnm->hwndFrom, TRUE);
				break;
			}
		}
        return(TRUE);

    
    }
    return(FALSE);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */


LRESULT APIENTRY RomListDialog(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
	/*~~~~~~~~~~~~~~~~~~~~~~~*/
	int		i;
	/*~~~~~~~~~~~~~~~~~~~~~~~*/

	switch(message)
	{
	case WM_INITDIALOG:
		TranslateDialag(hDlg, "ROM_OPTIONS");

		ROM_OPTION_SET_LISTBOX
		(
			IDC_ROMOPTION_RDRAMSIZE,
			3,
			defaultoptions.RDRAM_Size,
			romlist[rlstatus.selected_rom_index]->pinientry->RDRAM_Size,
			rdram_size_names
		);
		ROM_OPTION_SET_LISTBOX
		(
			IDC_ROMOPTION_SAVETYPE,
			7,
			defaultoptions.Save_Type,
			romlist[rlstatus.selected_rom_index]->pinientry->Save_Type,
			save_type_names
		);
		ROM_OPTION_SET_LISTBOX
		(
			IDC_ROMOPTION_CPUEMULATOR,
			3,
			defaultoptions.Emulator,
			romlist[rlstatus.selected_rom_index]->pinientry->Emulator,
			emulator_type_names
		);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_CODECHECK,
			9,
			defaultoptions.Code_Check,
			romlist[rlstatus.selected_rom_index]->pinientry->Code_Check,
			codecheck_type_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_MAXVISPEED,
			19,
			defaultoptions.Max_FPS,
			romlist[rlstatus.selected_rom_index]->pinientry->Max_FPS,
			maxfps_type_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_USETLB,
			3,
			defaultoptions.Use_TLB,
			romlist[rlstatus.selected_rom_index]->pinientry->Use_TLB,
			usetlb_type_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_EEPROMSIZE,
			4,
			defaultoptions.Eeprom_size,
			romlist[rlstatus.selected_rom_index]->pinientry->Eeprom_size,
			eepromsize_type_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_USEREGC,
			3,
			defaultoptions.Use_Register_Caching,
			romlist[rlstatus.selected_rom_index]->pinientry->Use_Register_Caching,
			register_caching_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_CF,
			9,
			defaultoptions.Counter_Factor,
			romlist[rlstatus.selected_rom_index]->pinientry->Counter_Factor,
			counter_factor_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_FPUHACK,
			3,
			defaultoptions.FPU_Hack,
			romlist[rlstatus.selected_rom_index]->pinientry->FPU_Hack,
			use_fpu_hack_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_TIMING_CONTROL,
			6,
			defaultoptions.timing_Control,
			romlist[rlstatus.selected_rom_index]->pinientry->timing_Control,
			timing_control_names
			);
		ROM_OPTION_SET_LISTBOX
			(
				IDC_ROMOPTION_LINK4KB,
				3,
				defaultoptions.Link_4KB_Blocks,
				romlist[rlstatus.selected_rom_index]->pinientry->Link_4KB_Blocks,
				use_4kb_link_block_names
			);
		ROM_OPTION_SET_LISTBOX
			(
				IDC_ROMOPTION_ANALYSIS,
				3,
				defaultoptions.Advanced_Block_Analysis,
				romlist[rlstatus.selected_rom_index]->pinientry->Advanced_Block_Analysis,
				use_block_analysis_names
			);
		ROM_OPTION_SET_LISTBOX
			(
				IDC_ROMOPTION_ASSUME_32BIT,
				3,
				defaultoptions.Assume_32bit,
				romlist[rlstatus.selected_rom_index]->pinientry->Assume_32bit,
				assume_32bit_names
			);
		ROM_OPTION_SET_LISTBOX
			(
				IDC_ROMOPTION_HLE,
				3,
				defaultoptions.Use_HLE,
				romlist[rlstatus.selected_rom_index]->pinientry->Use_HLE,
				use_HLE_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_SP_DP_TIMING,
			3,
			defaultoptions.RSP_RDP_Timing,
			romlist[rlstatus.selected_rom_index]->pinientry->RSP_RDP_Timing,
			use_RSP_RDP_Timing_names
			);
		ROM_OPTION_SET_LISTBOX
			(
			IDC_ROMOPTION_FRAMEBUFFER_R_W,
			3,
			defaultoptions.frame_buffer_rw,
			romlist[rlstatus.selected_rom_index]->pinientry->frame_buffer_rw,
			use_Frame_Buffer_R_W_names
			);

		SetDlgItemText(hDlg, IDC_ROMOPTION_COMMENTS, romlist[rlstatus.selected_rom_index]->pinientry->Comments);
		SetDlgItemText(hDlg, IDC_ROMOPTION_ALTTITLE, romlist[rlstatus.selected_rom_index]->pinientry->Alt_Title);

		return(TRUE);


    //Propertysheet handling
	case WM_NOTIFY:
		{
		LPNMHDR lpnm = (LPNMHDR) lParam;

        switch (lpnm->code)
            {
			case PSN_APPLY:
				SendMessage(hDlg, WM_COMMAND, IDOK, lParam);
                EndDialog(lpnm->hwndFrom, TRUE);
				break;

            case PSN_RESET :
                //Handle a Cancel button click, if necessary
                EndDialog(lpnm->hwndFrom, TRUE);
				break;
			}
		}
		return(TRUE);


	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
			{
				/* Read option setting from dialog */
				romlist[rlstatus.selected_rom_index]->pinientry->RDRAM_Size = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_RDRAMSIZE,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Save_Type = (GAMESAVETYPE)((int)SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_SAVETYPE,
						CB_GETCURSEL,
						0,
						0
					) + 1);
				romlist[rlstatus.selected_rom_index]->pinientry->Emulator = (EMULATORTYPE)((int)SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_CPUEMULATOR,
						CB_GETCURSEL,
						0,
						0
					) + 1);
				romlist[rlstatus.selected_rom_index]->pinientry->Code_Check = (CODECHECKTYPE)((int)SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_CODECHECK,
						CB_GETCURSEL,
						0,
						0
					) + 1);
				romlist[rlstatus.selected_rom_index]->pinientry->Max_FPS = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_MAXVISPEED,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Use_TLB = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_USETLB,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Eeprom_size = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_EEPROMSIZE,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Use_Register_Caching = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_USEREGC,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Counter_Factor = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_CF,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->FPU_Hack = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_FPUHACK,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->timing_Control = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_TIMING_CONTROL,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Link_4KB_Blocks = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_LINK4KB,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Advanced_Block_Analysis = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_ANALYSIS,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Assume_32bit = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_ASSUME_32BIT,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->Use_HLE = SendDlgItemMessage
					(
						hDlg,
						IDC_ROMOPTION_HLE,
						CB_GETCURSEL,
						0,
						0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->RSP_RDP_Timing = SendDlgItemMessage
					(
					hDlg,
					IDC_ROMOPTION_SP_DP_TIMING,
					CB_GETCURSEL,
					0,
					0
					) + 1;
				romlist[rlstatus.selected_rom_index]->pinientry->frame_buffer_rw = SendDlgItemMessage
					(
					hDlg,
					IDC_ROMOPTION_FRAMEBUFFER_R_W,
					CB_GETCURSEL,
					0,
					0
					) + 1;
				if
				(
					romlist[rlstatus.selected_rom_index]->pinientry->Code_Check != CODE_CHECK_PROTECT_MEMORY
				&&	romlist[rlstatus.selected_rom_index]->pinientry->Code_Check != CODE_CHECK_NONE
				&&	romlist[rlstatus.selected_rom_index]->pinientry->Link_4KB_Blocks == USE4KBLINKBLOCK_YES
				)
				{
					DisplayError("Link 4KB cannot be used when the self-mod code checking method is not PROTECT_MEMORY or No_Check, go to Game Options and set Link_4KB to No.");
					romlist[rlstatus.selected_rom_index]->pinientry->Link_4KB_Blocks = USE4KBLINKBLOCK_NO;
				}

				GetDlgItemText(hDlg, IDC_ROMOPTION_COMMENTS, romlist[rlstatus.selected_rom_index]->pinientry->Comments, 79);
				GetDlgItemText(hDlg, IDC_ROMOPTION_ALTTITLE, romlist[rlstatus.selected_rom_index]->pinientry->Alt_Title, 99);


				RomList_UpdateNameAndComments(rlstatus.selected_rom_index);

                FileIO_Write1964Ini();

				EndDialog(hDlg, TRUE);
				return(TRUE);
			}

		case IDCANCEL:
			{
				EndDialog(hDlg, TRUE);
				return(TRUE);
			}
		}
	}

	return(FALSE);
}

/*
 =======================================================================================================================
    Create a rom list entry for the rom loaded in memory
 =======================================================================================================================
 */
void __cdecl ReadRomHeaderInMemory(INI_ENTRY *ini_entry)
{
	/*~~~~~~~~~~~~~~~~~~*/
	uint8	buffer[0x100];
	/*~~~~~~~~~~~~~~~~~~*/

	memcpy(buffer, gMS_ROM_Image, 0x40);

	strncpy(ini_entry->Game_Name, (const char*)(buffer + 0x20), 0x14);
	SwapRomName((unsigned char*)ini_entry->Game_Name);

	ini_entry->crc1 = *((uint32 *) (buffer + 0x10));
	ini_entry->crc2 = *((uint32 *) (buffer + 0x14));
	ini_entry->countrycode = buffer[0x3D];
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void  __cdecl RomListSelectLoadedRomEntry(void)
{
	/*~~~~~~~~~~~~~~*/
	int			i;
	INI_ENTRY	entry;
	/*~~~~~~~~~~~~~~*/

	ReadRomHeaderInMemory(&entry);

	for(i = 0; i < rlstatus.romlist_count; i++)
	{
		//if( stricmp(romlist[i]->pinientry->Game_Name, entry.Game_Name) == 0 &&
			//romlist[i]->pinientry->crc1 == entry.crc1 &&
		if( romlist[i]->pinientry->crc1 == entry.crc1 && romlist[i]->pinientry->crc2 == entry.crc2 && romlist[i]->pinientry->countrycode == entry.countrycode )
		{
			break;
		}
	}

	rlstatus.selected_rom_index = i;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
ROMLIST_ENTRY * __cdecl RomListSelectedEntry(void)
{
	return romlist[rlstatus.selected_rom_index];
}

#define C_COLUMNS	6

typedef struct	myitem_tag
{
	LPSTR	aCols[C_COLUMNS];
} MYITEM;

extern int GetFullBitmapIndex(int index);
void ClearImageListMap(void);
int GetSmallIconIndex(int index)
{
	if( ImageList_GetImageCount(rlstatus.hSmallIcons) < 1 )
	{
		HICON   hIcon;

		hIcon = LoadIcon( gui.hInst, MAKEINTRESOURCE( IDI_PLAYABLE ) );
		ImageList_AddIcon( rlstatus.hSmallIcons, hIcon );

		hIcon = LoadIcon( gui.hInst, MAKEINTRESOURCE( IDI_ALMOST_PLAYABLE ) );
		ImageList_AddIcon( rlstatus.hSmallIcons, hIcon );

		hIcon = LoadIcon( gui.hInst, MAKEINTRESOURCE( IDI_NOT_PLAYABLE ) );
		ImageList_AddIcon( rlstatus.hSmallIcons, hIcon );

		hIcon = LoadIcon( gui.hInst, MAKEINTRESOURCE( IDI_UNKNOWN ) );
		ImageList_AddIcon( rlstatus.hSmallIcons, hIcon );
	}

	if (strstr(romlist[index]->pinientry->Comments, "Almost") != NULL)
    {
        return 1;
    }
    else if (strstr(romlist[index]->pinientry->Comments, "Not") != NULL)
    {
        return 2;
    }
    else if (strstr(romlist[index]->pinientry->Comments, "Playable") != NULL)
        return 0;
    else
    {
        return 3;
    }
}


/*
 =======================================================================================================================
    InitListViewItems - adds items and subitems to a list view. ?    Returns TRUE if successful, or FALSE otherwise. ?    hwndLV - handle to the list view control. ?    pfData - text file containing list view items with columns ?    separated by semicolons.
 =======================================================================================================================
 */

BOOL WINAPI InitListViewItems(HWND hwndLV, int Sorting)
{
	int		index, i;
	char	size[20];
	char	countryname[40];
	char	textbuf[100];
	int		tvsystem;
	LVITEM	lvi;
    LVCOLUMN colinfo;
    static int ImageListCreated = 0;

	int numberOfColumnsEnabled = 0;

    SendMessage(gui.hwndRomList, LVM_SETTEXTCOLOR, 0, 0x000000);
    SendMessage(gui.hwndRomList, LVM_SETBKCOLOR, 0, 0xffffff);

	if( guioptions.display_boxart )
	{
		DWORD space;
		ListView_SetImageList( hwndLV, rlstatus.hLargeBitmaps, LVSIL_NORMAL ); 
		rlstatus.iconXSpacing = guioptions.boxart_image_x_spacing;
		rlstatus.iconYSpacing = guioptions.boxart_image_y_spacing;
		space = ListView_SetIconSpacing(gui.hwndRomList,rlstatus.iconXSpacing+rlstatus.iconWidth,rlstatus.iconYSpacing+rlstatus.iconHeight);
	}
	else
		ListView_SetImageList( hwndLV, rlstatus.hSmallIcons, LVSIL_SMALL ); 

	/* Initialize LVITEM members that are common to all items. */
	lvi.mask = LVIF_TEXT | LVIF_STATE | LVIF_IMAGE;
	lvi.state = 0;
	lvi.stateMask = 0;
	lvi.pszText = LPSTR_TEXTCALLBACK;	/* app. maintains text */


	for( i=0; i<numberOfRomListColumns; i++ )
	{
		if( romListColumns[i].enabled )
			numberOfColumnsEnabled++;
	}

	/* Read each line in the specified file. */
	for(index = 0; index < rlstatus.romlist_count; index++)
	{
		BOOL display_comment = FALSE;
		char buf[512];
		buf[0] = 0;

		/* Initialize item-specific LVITEM members. */
		lvi.iItem = index;
		lvi.iSubItem = 0;

		RomListGetGoodRomNameToDisplay(generalmessage, index);
		lvi.pszText = generalmessage;

//        if (index == rlstatus.selected_rom_index)
  //          lvi.state |= LVIS_SELECTED | LVIS_GLOW;
        
		if( guioptions.display_boxart )
			lvi.iImage = GetFullBitmapIndex(index);
		else
			lvi.iImage = GetSmallIconIndex(index);

        if (!Sorting)
        {    
            ListView_InsertItem(hwndLV, &lvi);
        }
        else
            //To update icons
            ListView_SetItem(hwndLV, &lvi);

		CountryCodeToCountryName_and_TVSystem(romlist[index]->pinientry->countrycode, countryname, &tvsystem);

		colinfo.mask = LVCF_TEXT;
		colinfo.pszText = textbuf;
		colinfo.cchTextMax = 99;

		//for( i=0; i< numberOfRomListColumns; i++)
		for( i=0; i< numberOfColumnsEnabled; i++)
		{
			__try {
				ListView_GetColumn(hwndLV, i, &colinfo);
				if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[0].text)) == 0 )	//Rom Name
				{
					ListView_SetItemText(hwndLV, index, i, lvi.pszText);
					strcat(buf, lvi.pszText);
					strcat(buf, ", ");
				}

				if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[1].text)) == 0 )	//Country name
				{
					ListView_SetItemText(hwndLV, index, i, countryname);
					strcat(buf, countryname);
					strcat(buf, ", ");
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[2].text)) == 0 ) //Rom Size
				{
					int iSize = (romlist[index]->size << 3) >> 20;

					if (iSize >> 3 == 0) 
						sprintf(size, "%3d Mbit", (romlist[index]->size << 3) >> 20);
					else
						sprintf(size, "%3d MB", (romlist[index]->size << 3) >> 23);
					ListView_SetItemText(hwndLV, index, i, size);
					strcat(buf, size);
					strcat(buf, ", ");
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[3].text)) == 0 ) //Comments
				{
					display_comment = TRUE;
					ListView_SetItemText(hwndLV, index, i, romlist[index]->pinientry->Comments);
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[4].text)) == 0 ) //Game Save Type
				{
					ListView_SetItemText(hwndLV, index, i, save_type_names[romlist[index]->pinientry->Save_Type]);
					strcat(buf, save_type_names[romlist[index]->pinientry->Save_Type]);
					strcat(buf, ", ");
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[5].text)) == 0 ) //CIC_Chip
				{
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[6].text)) == 0 ) //CRC1
				{
					sprintf(size, "%08X", romlist[index]->pinientry->crc1);
					ListView_SetItemText(hwndLV, index, i, size);
					strcat(buf, size);
					strcat(buf, ", ");
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[7].text)) == 0 ) //CRC2
				{
					sprintf(size, "%08X", romlist[index]->pinientry->crc2);
					ListView_SetItemText(hwndLV, index, i, size);
					strcat(buf, size);
					strcat(buf, ", ");
				}
				else if( stricmp(colinfo.pszText, TranslateStringByString(romListColumns[8].text)) == 0 ) //Number Of Players
				{
					sprintf(size, "%d", romlist[index]->pinientry->numberOfPlayers);
					ListView_SetItemText(hwndLV, index, i, size);
					strcat(buf, size);
					strcat(buf, ", ");
				}

			}__except(NULL, EXCEPTION_EXECUTE_HANDLER)
			{
			}
		}

		if( display_comment && guioptions.display_boxart )
		{
			//int len = strlen(buf);
			//if( len > 10 )
			//{
			//	buf[len-2] = 0;
			//}
			strcat(buf, "\n");
			strcat(buf, romlist[index]->pinientry->Comments);
		}

		if( guioptions.display_boxart )
		{
			int len = strlen(buf);
			if( len > 10 )
			{
				if( !display_comment )
					buf[len-2] = 0;
			}
			ListView_SetItemText(hwndLV, index, 0, buf);
		}
	}

	if(rlstatus.romlist_count > 0) RomListSelectRom(rlstatus.selected_rom_index);

	return TRUE;
}

/*
 =======================================================================================================================
    InitListViewColumns - adds columns to a list view control. ?    Returns TRUE if successful, or FALSE otherwise. ?    hwndLV - handle to the list view control.
 =======================================================================================================================
 */
BOOL WINAPI InitListViewColumns(HWND hwndLV, int windowwidth)
{
	/*~~~~~~~~~~~~*/
	int i;
	LVCOLUMNA	lvc;
	/*~~~~~~~~~~~~*/

	/* Initialize the LVCOLUMN structure. */
	lvc.mask = LVCF_FMT | LVCF_WIDTH | LVCF_TEXT | LVCF_SUBITEM;
	lvc.fmt = LVCFMT_LEFT;

	for( i=0; i<numberOfRomListColumns; i++ )
	{
		if( romListColumns[i].enabled )
		{
			if( romListColumns[i].colWidth > 500 || romListColumns[i].colWidth < 0 )
			{
				romListColumns[i].colWidth = 50;
			}
			lvc.cx = romListColumns[i].colWidth;
			lvc.pszText = TranslateStringByString(romListColumns[i].text);
			lvc.iSubItem = i;
			ListView_InsertColumn(hwndLV, i, &lvc);
		}
	}
	return TRUE;
}

HWND WINAPI CreateRebar(HWND hwndOwner)
{
   REBARINFO     rbi;
   REBARBANDINFO rbBand;
   HWND   hwndRB;
   DWORD  dwBtnSize;
   INITCOMMONCONTROLSEX icex;
   
   icex.dwSize = sizeof(INITCOMMONCONTROLSEX);
   icex.dwICC   = ICC_COOL_CLASSES|ICC_BAR_CLASSES;
   InitCommonControlsEx(&icex);
   hwndRB = CreateWindowEx(WS_EX_TOOLWINDOW,
                           REBARCLASSNAME,
                           NULL,
                           WS_CHILD|WS_VISIBLE|WS_CLIPSIBLINGS|
                           WS_CLIPCHILDREN|RBS_VARHEIGHT|
                           CCS_NODIVIDER,
                           0,0,0,0,
                           gui.hwnd1964main,
                           NULL,
                           gui.hInst,
                           NULL);
   if(!hwndRB)
      return NULL;
   // Initialize and send the REBARINFO structure.
   rbi.cbSize = sizeof(REBARINFO);  // Required when using this
                                    // structure.
   rbi.fMask  = 0;
   rbi.himl   = (HIMAGELIST)NULL;
   if(!SendMessage(hwndRB, RB_SETBARINFO, 0, (LPARAM)&rbi))
      return NULL;
   // Initialize structure members that both bands will share.
   rbBand.cbSize = sizeof(REBARBANDINFO);  // Required
   rbBand.fMask  = RBBIM_COLORS | RBBIM_TEXT /*| RBBIM_BACKGROUND */| 
                   RBBIM_STYLE | RBBIM_CHILD | RBBIM_CHILDSIZE | 
                   RBBIM_SIZE;
   rbBand.fStyle = RBBS_CHILDEDGE;
 
   // Get the height of the toolbar.
   dwBtnSize = SendMessage(gui.hToolBar, TB_GETBUTTONSIZE, 0,0);

   // Set values unique to the band with the toolbar.
   rbBand.lpText     = "";
   rbBand.hwndChild  = gui.hToolBar;
   rbBand.cxMinChild = 0;
   rbBand.cyMinChild = HIWORD(dwBtnSize);
   rbBand.cx         = 250;
	rbBand.clrFore = GetSysColor(COLOR_BTNTEXT);
	rbBand.clrBack = GetSysColor(COLOR_BTNFACE);
   // Add the band that has the toolbar.
   SendMessage(hwndRB, RB_INSERTBAND, (WPARAM)-1, (LPARAM)&rbBand);
   return (hwndRB);
}

void  __cdecl EnableRadioButtons( BOOL bEnable )
{
	EnableButton(ID_BUTTON_PLAY, bEnable);
	CheckButton(ID_BUTTON_PLAY, FALSE);
	EnableButton(ID_BUTTON_PAUSE, bEnable);
	CheckButton(ID_BUTTON_PAUSE, FALSE);
	EnableButton(ID_BUTTON_STOP, bEnable);
	CheckButton(ID_BUTTON_STOP, FALSE);
	EnableButton(ID_BUTTON_RESET, bEnable);
	CheckButton(ID_BUTTON_RESET, FALSE);

	//Enable or disable buttons and menus that open a web browser
	EnableButton(ID_BUTTON_HELP, bEnable^1);
	EnableButton(ID_BUTTON_HOME_PAGE, bEnable^1);
	EnableButton(ID_BUTTON_OPEN_ROM, bEnable^1);
	if (bEnable == TRUE)
	{
		EnableMenuItem(gui.hMenu1964main, ID_CHECKWEB, MF_GRAYED);
		EnableMenuItem(gui.hMenu1964main, ID_OPENROM, MF_GRAYED);
		EnableMenuItem(gui.hMenu1964main, ID_ONLINE_HELP, MF_GRAYED);
	}
	else
	{
		EnableMenuItem(gui.hMenu1964main, ID_CHECKWEB, MF_ENABLED);
		EnableMenuItem(gui.hMenu1964main, ID_OPENROM, MF_ENABLED);
		EnableMenuItem(gui.hMenu1964main, ID_ONLINE_HELP, MF_ENABLED);
	}
}

BYTE __cdecl ChangeButtonState( int	nID )
{
	TBBUTTONINFO ButtonInfo;
	int temp;

	ButtonInfo.cbSize = sizeof(TBBUTTONINFO);
	ButtonInfo.dwMask = TBIF_STATE;

	SendMessage(gui.hToolBar, TB_GETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);

	ButtonInfo.fsState ^= TBSTATE_CHECKED;
	temp = ButtonInfo.fsState;

	SendMessage(gui.hToolBar, TB_SETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);

	return (temp);
}

BYTE __cdecl GetButtonState( int	nID )
{
	TBBUTTONINFO ButtonInfo;
	int temp;

	ButtonInfo.cbSize = sizeof(TBBUTTONINFO);
	ButtonInfo.dwMask = TBIF_STATE;

	SendMessage(gui.hToolBar, TB_GETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);

	temp = ButtonInfo.fsState;

	return (temp);
}



void __cdecl CheckButton( int	nID, 
			 BOOL	bCheck )
{
	TBBUTTONINFO ButtonInfo;

	ButtonInfo.cbSize = sizeof(TBBUTTONINFO);
	ButtonInfo.dwMask = TBIF_STATE;

	SendMessage(gui.hToolBar, TB_GETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);

	if (bCheck)
		ButtonInfo.fsState |= TBSTATE_CHECKED;
	else
		ButtonInfo.fsState &= ~TBSTATE_CHECKED;

	SendMessage(gui.hToolBar, TB_SETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);
}

void __cdecl EnableButton( int	nID, 
			  BOOL	bEnable)
{
	TBBUTTONINFO ButtonInfo;

	ButtonInfo.cbSize = sizeof(TBBUTTONINFO);
	ButtonInfo.dwMask = TBIF_STATE;

	SendMessage(gui.hToolBar, TB_GETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);

	if (bEnable)
		ButtonInfo.fsState |= TBSTATE_ENABLED;
	else
	{
		ButtonInfo.fsState &= ~TBSTATE_CHECKED;
		ButtonInfo.fsState &= ~TBSTATE_ENABLED;
	}

	SendMessage(gui.hToolBar, TB_SETBUTTONINFO, nID,
	(LPARAM)(LPTBBUTTONINFO) &ButtonInfo);
}


void  __cdecl SetupToolBar()
{
		TBADDBITMAP tbab;
         TBBUTTON tbb[16];

      	gui.hToolBar = CreateWindowEx
		(	
			0, 
			TOOLBARCLASSNAME, 
			NULL,
		    WS_CHILD | WS_VISIBLE | TBSTYLE_FLAT | TBSTYLE_TRANSPARENT | TBSTYLE_TOOLTIPS
			| WS_CLIPCHILDREN |
			WS_CLIPSIBLINGS | CCS_NODIVIDER,
			0, 
			0, 
			0, 
			0,
	        gui.hwnd1964main, 
			(HMENU)IDR_TOOLBAR1, 
			(HINSTANCE) gui.hInst, 
			NULL
		);

		 // Send the TB_BUTTONSTRUCTSIZE message, which is required for
         // backward compatibility.
         SendMessage(gui.hToolBar, TB_BUTTONSTRUCTSIZE, (WPARAM)sizeof(TBBUTTON), 0);

         tbab.hInst = gui.hInst;
         tbab.nID = IDR_TOOLBAR1;
         SendMessage(gui.hToolBar, TB_ADDBITMAP, 4, (LPARAM)&tbab);

         ZeroMemory(tbb, sizeof(tbb));
         
     	 tbb[0].iBitmap = 0;
         tbb[0].fsState = TBSTATE_ENABLED;
         tbb[0].fsStyle = TBSTYLE_BUTTON;
         tbb[0].idCommand = ID_BUTTON_OPEN_ROM;

         tbb[1].fsStyle = TBSTYLE_SEP;

		 tbb[2].iBitmap = 4;
         tbb[2].fsState = TBSTATE_ENABLED;
         tbb[2].fsStyle = TBSTYLE_CHECKGROUP;
         tbb[2].idCommand = ID_BUTTON_PLAY;

		 tbb[3].iBitmap = 5;
         tbb[3].fsState = TBSTATE_ENABLED;
         tbb[3].fsStyle = TBSTYLE_CHECKGROUP;
         tbb[3].idCommand = ID_BUTTON_PAUSE;

		 tbb[4].iBitmap = 6;
         tbb[4].fsState = TBSTATE_ENABLED;
         tbb[4].fsStyle = TBSTYLE_BUTTON; 
         tbb[4].idCommand = ID_BUTTON_STOP;

		 tbb[5].iBitmap = 8;
         tbb[5].fsState = TBSTATE_ENABLED;
         tbb[5].fsStyle = TBSTYLE_BUTTON;
         tbb[5].idCommand = ID_BUTTON_RESET;

		 tbb[6].fsStyle = TBSTYLE_SEP;
		 
         tbb[7].iBitmap = 7;
         tbb[7].fsState = TBSTATE_ENABLED;
         tbb[7].fsStyle = TBSTYLE_BUTTON;
         tbb[7].idCommand = ID_BUTTON_SETUP_PLUGINS;

         tbb[8].iBitmap = 3;
         tbb[8].fsState = TBSTATE_ENABLED;
         tbb[8].fsStyle = TBSTYLE_BUTTON;
         tbb[8].idCommand = ID_BUTTON_ROM_PROPERTIES;
		 
         tbb[9].iBitmap = 9;
         tbb[9].fsState = TBSTATE_ENABLED;
         tbb[9].fsStyle = TBSTYLE_BUTTON;
         tbb[9].idCommand = ID_BUTTON_HELP;

		 tbb[10].iBitmap = 2;
         tbb[10].fsState = TBSTATE_ENABLED;
         tbb[10].fsStyle = TBSTYLE_BUTTON;
         tbb[10].idCommand = ID_BUTTON_HOME_PAGE;

		 tbb[11].fsStyle = TBSTYLE_SEP;


		 tbb[12].iBitmap = 11;
         tbb[12].fsState = TBSTATE_ENABLED;

         if (emuoptions.SyncVI)
             tbb[12].fsState|= TBSTATE_CHECKED;
         tbb[12].fsStyle = TBSTYLE_CHECK;
         tbb[12].idCommand = ID_BUTTON_SYNC_SPEED;
                
         tbb[13].iBitmap = 1;
         tbb[13].fsState = TBSTATE_ENABLED;
         tbb[13].fsStyle = TBSTYLE_BUTTON;
         tbb[13].idCommand = ID_BUTTON_FULL_SCREEN;

         SendMessage(gui.hToolBar, TB_ADDBUTTONS, 14, (LPARAM)&tbb);
		 gui.hReBar = CreateRebar(gui.hwnd1964main);
}


/*
 =======================================================================================================================
 =======================================================================================================================
 */
HWND __cdecl NewRomList_CreateListViewControl( HWND hwndParent )
{
	RECT	rcParent;
	DWORD	style;

	if(!guioptions.display_romlist) return NULL;

	/*
	 * Ensure that the common control DLL is loaded, and then create ?	 * the header control.
	 */
	InitCommonControls();
	GetClientRect(hwndParent, &rcParent);

	if(gui.hStatusBar != NULL)
	{
		/*~~~~~~~~~~~~~~~~*/
		RECT	rcStatusBar;
		/*~~~~~~~~~~~~~~~~*/

		GetWindowRect(gui.hStatusBar, &rcStatusBar);
		rcParent.bottom -= (rcStatusBar.bottom - rcStatusBar.top - 1);
	}

	if(gui.hToolBar != NULL)
	{
		/*~~~~~~~~~~~~~~~~*/
		RECT	rcToolBar;
		/*~~~~~~~~~~~~~~~~*/

		GetWindowRect(gui.hToolBar, &rcToolBar);
		rcParent.top += (rcToolBar.bottom - rcToolBar.top - 1);
		rcParent.bottom -= (rcToolBar.bottom - rcToolBar.top - 1);
	}

	style = guioptions.display_boxart==TRUE?LVS_ICON:LVS_REPORT;

	/* Create the list view window. */
	gui.hwndRomList = CreateWindow
		(
			WC_LISTVIEW,
			"",
			//WS_CHILD | LVS_REPORT | LVS_SINGLESEL,
			WS_CHILD | style | LVS_SINGLESEL | LVS_SHAREIMAGELISTS,
			0,
			rcParent.top,
			rcParent.right,
			rcParent.bottom,
			hwndParent,
			NULL,
			gui.hInst,
			NULL
		);

	if(gui.hwndRomList == NULL)
	{
		DisplayError("Error to create listview");
		return NULL;
	}

	if( rlstatus.hLargeBitmaps != NULL && 
		(rlstatus.iconWidth != guioptions.boxart_image_width || rlstatus.iconHeight != guioptions.boxart_image_height ||
		rlstatus.iconXSpacing != guioptions.boxart_image_x_spacing || rlstatus.iconYSpacing != guioptions.boxart_image_y_spacing ) )
	{
		ImageList_Destroy(rlstatus.hLargeBitmaps);
		ClearImageListMap();
		rlstatus.hLargeBitmaps = NULL;
	}	

	if( rlstatus.hLargeBitmaps == NULL )
	{
		rlstatus.iconWidth = guioptions.boxart_image_width;
		rlstatus.iconHeight = guioptions.boxart_image_height;
		rlstatus.hLargeBitmaps = ImageList_Create( rlstatus.iconWidth, rlstatus.iconHeight, ILC_COLOR32|ILC_MASK, 2, 10 );
	}

	if( rlstatus.hSmallIcons == NULL )
	{
		rlstatus.hSmallIcons = ImageList_Create( 16, 15, ILC_COLOR32|ILC_MASK, 6, 0 );
	}


	InitListViewColumns(gui.hwndRomList, rcParent.right);
	InitListViewItems(gui.hwndRomList, 0);

	ListView_SetExtendedListViewStyle(gui.hwndRomList, LVS_EX_FULLROWSELECT);	/* | LVS_EX_TRACKSELECT ); */

	/* ListView_SetHoverTime(hwndLV, 3000); */
	ShowWindow(gui.hwndRomList, SW_SHOW);
	UpdateWindow(gui.hwndRomList);
	if(rlstatus.romlist_count > 0) RomListSelectRom(rlstatus.selected_rom_index);

	return gui.hwndRomList;	/* return the control's handle */
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl NewRomList_ListViewHideHeader( HWND hwnd )
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	DWORD	dwStyle = GetWindowLong(hwnd, GWL_STYLE);
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	SetWindowLong(hwnd, GWL_STYLE, dwStyle | LVS_NOCOLUMNHEADER);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl NewRomList_ListViewShowHeader( HWND hwnd )
{
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/
	DWORD	dwStyle = GetWindowLong(hwnd, GWL_STYLE);
	/*~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~*/

	SetWindowLong(hwnd, GWL_STYLE, dwStyle &~LVS_NOCOLUMNHEADER);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl NewRomList_ListViewFreshRomList( void )
{
	ListView_DeleteAllItems(gui.hwndRomList);
	NewRomList_Sort();
	InitListViewItems(gui.hwndRomList, 0);
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void _cdecl NewRomList_ListViewChangeWindowRect( void )
{
	RomListRememberColumnWidth();
	ListView_DeleteAllItems(gui.hwndRomList);
	DestroyWindow(gui.hwndRomList);
	gui.hwndRomList = NewRomList_CreateListViewControl(gui.hwnd1964main);
}

/*
 =======================================================================================================================
    Sort the rom list according to parameter rlstatus.romlist_sort_method
 =======================================================================================================================
 */
BOOL
_cdecl
InternalNameIsValid( char *name )
{
	/*~~~~~~~~~~~~~~~~~~~~~*/
	BOOL	valid = FALSE;
	int		i;
	int		n = strlen(name);
	/*~~~~~~~~~~~~~~~~~~~~~*/

	if(n > 20) n = 20;
	for(i = 0; i < n; i++)
	{
		if((unsigned char) (name[i]) > 0x7F)
		{
			valid = FALSE;
			break;
		}
		else if(name[i] != ' ')
			valid = TRUE;
	}

	return valid;
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl NewRomList_Sort()
{
	struct ROMLIST_ENTRY_STRUCT *temp;
	int							i, j;
	BOOL						needswap;
	char						cname1[10], cname2[10];
	char						gamename1[200], gamename2[200];
	int							tv1, tv2;
	int							retval;
    int                         sort_method_mod = rlstatus.romlist_sort_method%NUM_SORT_METHODS;
	

	TRACE1("Sort rom list: %d", rlstatus.romlist_count);

    needswap = FALSE;
    for(i = 0; i < rlstatus.romlist_count - 1; i++)

    {
		RomListGetGoodRomNameToDisplay(gamename1, i);
		
		for(j = i + 1; j < rlstatus.romlist_count; j++)
		{
			RomListGetGoodRomNameToDisplay(gamename2, j);
			switch(sort_method_mod)
			{
			case ROMLIST_GAMENAME:
				if(stricmp(gamename1, gamename2) >= 0) needswap = TRUE;
				break;
			case ROMLIST_COUNTRY:
				CountryCodeToCountryName_and_TVSystem(romlist[i]->pinientry->countrycode, cname1, &tv1);
                CountryCodeToCountryName_and_TVSystem(romlist[j]->pinientry->countrycode, cname2, &tv2);
				retval = stricmp(cname1, cname2);
				if( retval > 0)
				{
					needswap = TRUE;
				}
				else if( retval == 0 )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}
				break;
			case ROMLIST_SIZE:
				if(romlist[i]->size > romlist[j]->size)
				{
					needswap = TRUE;
				}
				else if( romlist[i]->size == romlist[j]->size )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}
				break;
			case ROMLIST_COMMENT:
				retval = stricmp(romlist[i]->pinientry->Comments, romlist[j]->pinientry->Comments);

				if(retval > 0)
				{
					needswap = TRUE;
                }
				else if( retval == 0 )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}

                break;
            case ROMLIST_SAVETYPE:
            
				if (romlist[i]->pinientry->Save_Type > romlist[j]->pinientry->Save_Type)
				{
					needswap = TRUE;
                }
				else if( romlist[i]->pinientry->Save_Type == romlist[j]->pinientry->Save_Type )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}
                break;

            case ROMLIST_CRC1:
            
				if (romlist[i]->pinientry->crc1 > romlist[j]->pinientry->crc1)
				{
					needswap = TRUE;
                }
				else if( romlist[i]->pinientry->crc1 == romlist[j]->pinientry->crc1 )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}

                break;

            case ROMLIST_CRC2:
            
				if (romlist[i]->pinientry->crc2 > romlist[j]->pinientry->crc2)
				{
					needswap = TRUE;
                }
				else if( romlist[i]->pinientry->crc2 == romlist[j]->pinientry->crc2 )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}

                break;

			case ROMLIST_PLAYERS:

				if (romlist[i]->pinientry->numberOfPlayers > romlist[j]->pinientry->numberOfPlayers)
				{
					needswap = TRUE;
				}
				else if( romlist[i]->pinientry->numberOfPlayers == romlist[j]->pinientry->numberOfPlayers )
				{
					if(stricmp(gamename1, gamename2) >= 0)
					{
						needswap = TRUE;
					}
				}
				break;
            }

            if(rlstatus.romlist_sort_method >= NUM_SORT_METHODS)
			{
				needswap ^= 1;
			}

			if(needswap)
			{
				needswap = FALSE;
                temp = romlist[i];
				romlist[i] = romlist[j];
				romlist[j] = temp;
				RomListGetGoodRomNameToDisplay(gamename1, i);
				CountryCodeToCountryName_and_TVSystem(romlist[i]->pinientry->countrycode, cname1, &tv1);
			}
		}
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListSaveCurrentPos(void)
{
	RomListRememberColumnWidth();
}

void RomListSaveCurrentPosToRegistry(void)
{
	POINT	pos;
	RECT	itemrect;

	int itemNo = SendMessage(gui.hwndRomList, LVM_GETSELECTIONMARK, 0, 0);

	if (itemNo > -1)
	{
		RomListSelectRom(itemNo);
	}

	REGISTRY_WriteDWORD("SelectedRomIndex", (DWORD)rlstatus.selected_rom_index);
	if( guioptions.display_boxart )
	{
		ListView_GetItemRect(gui.hwndRomList, rlstatus.selected_rom_index, &itemrect, LVIR_ICON);
		REGISTRY_WriteDWORD("SelectedRomPos", (DWORD)itemrect.top);
	}
	else
	{
		ListView_GetItemPosition(gui.hwndRomList, rlstatus.selected_rom_index, &pos);
		REGISTRY_WriteDWORD("SelectedRomPos", (DWORD)pos.y);
	}
}

void RomListLoadCurrentPosFromRegistry(void)
{
	int index;

	index = REGISTRY_ReadDWORD("SelectedRomIndex",0);

	if(index < rlstatus.romlist_count)
	{
		POINT	pos;
		RECT	itemrect;

		int		posy;
		RomListSelectRom(index);
		posy = REGISTRY_ReadDWORD("SelectedRomPos",0);
		if( guioptions.display_boxart )
		{
			ListView_GetItemRect(gui.hwndRomList, rlstatus.selected_rom_index, &itemrect, LVIR_ICON);
			ListView_Scroll(gui.hwndRomList, 0, itemrect.top-posy);
		}
		else
		{
			ListView_GetItemPosition(gui.hwndRomList, rlstatus.selected_rom_index, &pos);
			ListView_Scroll(gui.hwndRomList, 0, pos.y-posy);
		}
		SetFocus(gui.hwndRomList);
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListUseSavedPos( void )
{
	POINT	newpos;
	RECT	viewrect;
	RECT	itemrect;

	if( guioptions.display_boxart )
	{
		ListView_GetViewRect(gui.hwndRomList, &viewrect);
		ListView_GetItemRect(gui.hwndRomList, rlstatus.selected_rom_index, &itemrect, LVIR_ICON);
		ListView_Scroll(gui.hwndRomList, 0, itemrect.top-savedItemRect.top);
	}
	else
	{
		ListView_GetItemPosition(gui.hwndRomList, rlstatus.selected_rom_index, &newpos);
		ListView_Scroll(gui.hwndRomList, 0, newpos.y-savedPosition.y);
	}
}

/*
 =======================================================================================================================
 =======================================================================================================================
 */
void __cdecl RomListRememberColumnWidth(void)
{
	int i;
	char	textbuf[100];
	LVCOLUMN colinfo;

	colinfo.mask = LVCF_TEXT;
	colinfo.pszText = textbuf;
	colinfo.cchTextMax = 99;
	
	for( i=0; i< numberOfRomListColumns; i++)
	{
		if( ListView_GetColumn(gui.hwndRomList, i, &colinfo) )
		{
			int col=GetColumnIDByName(colinfo.pszText);
			int width = ListView_GetColumnWidth(gui.hwndRomList, i);
			if( width == 0 && i == 0 )
				return;	// Don't remember the widths 

			romListColumns[col].colWidth = width;
			if( romListColumns[col].colWidth <= 0 )
			{
				romListColumns[col].colWidth = 50;
			}
		}
	}
}



/*
 =======================================================================================================================
 =======================================================================================================================
 */
ROMLIST_ENTRY * __cdecl RomListGet_Selected_Entry(void)
{
	return romlist[rlstatus.selected_rom_index];
}

/*
 =======================================================================================================================
    Sort the rom list according to parameter rlstatus.romlist_sort_method
 =======================================================================================================================
 */
void __cdecl ConvertInvalidInternalName( char *oldname, char *newname )
{
	/*~~~~~~~~~~~~~~~~~~~~*/
	int i;
	int n = strlen(oldname);
	/*~~~~~~~~~~~~~~~~~~~~*/

	if(n > 20) n = 20;
	for(i = 0; i < n; i++)
	{
		if((unsigned char) (oldname[i]) > 0x7F)
		{
			newname[i] = oldname[i] - 0x7F;
			if(newname[i] < 0x20) newname[i] += 0x20;
		}
		else
		{
			newname[i] = oldname[i];
		}
	}

	newname[i] = '\0';
}


#define ASCENDING  1
#define DESCENDING 2

//Alwas use this function when sorting columns.
//It will sort the correct column properly, even if you remove some columns.
//To sort inverted, set Order to ASCENDING|DESCENDING.
void NewRomList_SortColumn(int column, int Order)
{
    char	        textbuf[100];
    //int             method;
    LVCOLUMN        colinfo;

    colinfo.mask = LVCF_TEXT;
    colinfo.pszText = textbuf;
	colinfo.cchTextMax = 99;

    ListView_GetColumn(gui.hwndRomList, column, &colinfo);
    rlstatus.romListHeaderClickedColumn=GetColumnIDByName(colinfo.pszText);

    if (Order == (ASCENDING|DESCENDING) )
    {
        if (rlstatus.romlist_sort_method >= NUM_SORT_METHODS)
            rlstatus.romlist_sort_method = 0;
         else
            rlstatus.romlist_sort_method = NUM_SORT_METHODS;
    }
    else if (Order == ASCENDING)
        rlstatus.romlist_sort_method = 0;
    else if (Order == DESCENDING)
        rlstatus.romlist_sort_method = NUM_SORT_METHODS;

    rlstatus.romlist_sort_method += rlstatus.romListHeaderClickedColumn;
	NewRomList_Sort();
	InitListViewItems(gui.hwndRomList, 1);

}


long __cdecl OnNotifyRomList(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	if(!emustatus.Emu_Is_Running)
	{
		int itemNo = ((LPNMLISTVIEW) lParam)->iItem;
		
        switch(((LPNMHDR) lParam)->code)
		{

        case NM_RETURN:
            itemNo = SendMessage(gui.hwndRomList, LVM_GETSELECTIONMARK, 0, 0);
           
			if (itemNo > -1)
            {
                EnableButton(ID_BUTTON_OPEN_ROM, FALSE);
			    EnableMenuItem(gui.hMenu1964main, ID_OPENROM, MF_GRAYED);

                RomListSelectRom(itemNo);
			    RomListOpenRom(itemNo, 1);
            }
			break;


        case NM_DBLCLK:
			EnableButton(ID_BUTTON_OPEN_ROM, FALSE);
			EnableMenuItem(gui.hMenu1964main, ID_OPENROM, MF_GRAYED);

            RomListSelectRom(((LPNMLISTVIEW) lParam)->iItem);
			RomListOpenRom(((LPNMLISTVIEW) lParam)->iItem, 1);
			break;

        case NM_RCLICK:
			if( itemNo >= 0 )
			{
				RECT pos;
				HMENU popupmainmenu, popupmenu;

				int x = ((LPNMLISTVIEW) lParam)->ptAction.x;
				int y = ((LPNMLISTVIEW) lParam)->ptAction.y;

                RomListSelectRom(((LPNMLISTVIEW) lParam)->iItem);
				EnableMenuItem(gui.hMenu1964main, ID_FILE_ROMINFO, MF_ENABLED);
				EnableButton(ID_BUTTON_ROM_PROPERTIES, TRUE);
				EnableMenuItem(gui.hMenu1964main, ID_FILE_CHEAT, MF_ENABLED);

				GetWindowRect(gui.hwndRomList, &pos);
				x+=pos.left;
				y+=pos.top;
				
				//popupmenu = GetSubMenu(gui.hMenu1964main, 2);
				popupmainmenu = LoadMenu(gui.hInst, "ROM_POPUP_MENU");
				popupmenu = GetSubMenu(popupmainmenu,0);
				if( !guioptions.display_boxart )
				{
					EnableMenuItem(popupmenu, ID_POPUPMENU_ASSIGNBOXARTIMAGE, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_POPUPMENU_REMOVEBOXARTIMAGELINK, MF_GRAYED);
				}
				else if( strlen(romlist[rlstatus.selected_rom_index]->pinientry->iconFilename) == 0 )
				{
					EnableMenuItem(popupmenu, ID_POPUPMENU_REMOVEBOXARTIMAGELINK, MF_GRAYED);
				}

				TranslateRomPopupMenu(popupmenu);
				TrackPopupMenuEx(popupmenu, TPM_VERTICAL, x, y, gui.hwnd1964main, NULL);
				DestroyMenu(popupmenu);
			}
			else
			{
				// Right clicked on white space
				RECT pos;
				HMENU popupmainmenu, popupmenu;

				int x = ((LPNMLISTVIEW) lParam)->ptAction.x;
				int y = ((LPNMLISTVIEW) lParam)->ptAction.y;

				GetWindowRect(gui.hwndRomList, &pos);
				x+=pos.left;
				y+=pos.top;

				popupmainmenu = LoadMenu(gui.hInst, "ROM_POPUP_MENU");
				popupmenu = GetSubMenu(popupmainmenu,3);

				if( !guioptions.display_boxart )
				{
					CheckMenuItem(popupmenu, ID_HEADERPOPUP3_SHOWROMLIST, MF_CHECKED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_ZOOM_IN,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_ZOOM_OUT,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_DECREASEXSPACING,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_INCREASEXSPACING,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_DECREASEYSPACING,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_BOXARTIMAGE_INCREASEYSPACING,MF_GRAYED);
					EnableMenuItem(popupmenu, ID_POPUPMENU_REMOVEBOXARTIMAGELINK, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_SHOW_INTERNAL_NAME, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_SHOWALTERNATEROMNAME, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_SHOWROMFILENAME, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_ASCENDING, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_DESCENDING, MF_GRAYED);
				}
				else
				{
					CheckMenuItem(popupmenu, ID_HEADERPOPUP3_SHOWBOXART, MF_CHECKED);

					switch( rlstatus.romlistNameToDisplay )
					{
					case ROMLIST_DISPLAY_INTERNAL_NAME:
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOW_INTERNAL_NAME, MF_CHECKED);
						break;
					case ROMLIST_DISPLAY_ALTER_NAME:
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOWALTERNATEROMNAME, MF_CHECKED);
						break;
					case ROMLIST_DISPLAY_FILENAME:
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOWROMFILENAME, MF_CHECKED);
						break;
					}

					if( rlstatus.romlist_sort_method == 0 )
					{
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_ASCENDING, MF_CHECKED);
					}
					else if( rlstatus.romlist_sort_method == NUM_SORT_METHODS )
					{
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_DESCENDING, MF_CHECKED);
					}

				}

				TranslatePopupMenu3(popupmenu);
				TrackPopupMenuEx(popupmenu, TPM_VERTICAL, x, y, gui.hwnd1964main, NULL);
				DestroyMenu(popupmenu);
			}
			break;

        case NM_CLICK:
			
            RomListSelectRom(((LPNMLISTVIEW) lParam)->iItem);
			EnableMenuItem(gui.hMenu1964main, ID_FILE_ROMINFO, MF_ENABLED);
			EnableButton(ID_BUTTON_ROM_PROPERTIES, TRUE);
			EnableMenuItem(gui.hMenu1964main, ID_FILE_CHEAT, MF_ENABLED);
			break;
		
//        case LVN_ITEMCHANGED:
    //        break;

        case LVN_COLUMNCLICK:
            {
            LPNMLISTVIEW	p = (LPNMLISTVIEW) lParam;
            if(p->iItem == -1 && p->uOldState == 0)
            {
                NewRomList_SortColumn(p->iSubItem, ASCENDING|DESCENDING);
            }
            }
            break;
		default:
			return(DefWindowProc(hWnd, message, wParam, lParam));
			break;
		}
	}
	
	return(0l);
}

long __cdecl OnNotifyRomListHeader(HWND hWnd, UINT message, WPARAM wParam, LPARAM lParam)
{
	HWND hWndHeader = ListView_GetHeader(gui.hwndRomList);

    switch(((LPNMHDR) lParam)->code)
	{

    
    case NM_RCLICK:
		{
			HMENU popupmainmenu, popupmenu;
			POINTS pts;
			POINT point;
			RECT rect;
			DWORD pos = GetMessagePos();
			pts = MAKEPOINTS(pos);
			point.x = pts.x;
			point.y = pts.y;
			ScreenToClient(hWndHeader, &point);
			popupmainmenu = LoadMenu(gui.hInst, "ROM_POPUP_MENU");
			
			for( rlstatus.romListHeaderClickedColumn=0; rlstatus.romListHeaderClickedColumn<numberOfRomListColumns; rlstatus.romListHeaderClickedColumn++)
			{
				Header_GetItemRect(hWndHeader, rlstatus.romListHeaderClickedColumn, &rect);
				if( PtInRect(&rect, point) )
				{
					break;
				}
			}
			
			if( rlstatus.romListHeaderClickedColumn == 0 )
			{
				popupmenu = GetSubMenu(popupmainmenu,1);
				TranslateColumnPopupMenu1(popupmenu);

				switch( rlstatus.romlistNameToDisplay )
				{
				case ROMLIST_DISPLAY_INTERNAL_NAME:
					CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOW_INTERNAL_NAME, MF_CHECKED);
					break;
				case ROMLIST_DISPLAY_ALTER_NAME:
					CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOWALTERNATEROMNAME, MF_CHECKED);
					break;
				case ROMLIST_DISPLAY_FILENAME:
					CheckMenuItem(popupmenu, ID_HEADERPOPUP_SHOWROMFILENAME, MF_CHECKED);
					break;
				}
				
				if( rlstatus.romlist_sort_method == 0 )
				{
					CheckMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_ASCENDING, MF_CHECKED);
				}
				else if( rlstatus.romlist_sort_method == NUM_SORT_METHODS )
				{
					CheckMenuItem(popupmenu, ID_HEADERPOPUP_1_SORT_DESCENDING, MF_CHECKED);
				}
				
			}
			else if( rlstatus.romListHeaderClickedColumn < numberOfRomListColumns )
			{
				char	textbuf[100];
				LVCOLUMN colinfo;
				colinfo.mask = LVCF_TEXT;
				colinfo.pszText = textbuf;
				colinfo.cchTextMax = 99;
				
				if( ListView_GetColumn(gui.hwndRomList, rlstatus.romListHeaderClickedColumn, &colinfo) )
				{
					rlstatus.romListHeaderClickedColumn=GetColumnIDByName(colinfo.pszText);
				}

				popupmenu = GetSubMenu(popupmainmenu,2);
				TranslateColumnPopupMenu2(popupmenu);

				if( rlstatus.romListHeaderClickedColumn < NUM_SORT_METHODS )
				{
					if( rlstatus.romlist_sort_method == rlstatus.romListHeaderClickedColumn )
					{
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_2_SORT_ASCENDING, MF_CHECKED);
					}
					else if( rlstatus.romlist_sort_method == rlstatus.romListHeaderClickedColumn+NUM_SORT_METHODS )
					{
						CheckMenuItem(popupmenu, ID_HEADERPOPUP_2_SORT_DESCENDING, MF_CHECKED);
					}
				}
				else
				{
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_2_SORT_ASCENDING, MF_GRAYED);
					EnableMenuItem(popupmenu, ID_HEADERPOPUP_2_SORT_DESCENDING, MF_GRAYED);
				}
			}
			
			TrackPopupMenuEx(popupmenu, TPM_VERTICAL, pts.x, pts.y, gui.hwnd1964main, NULL);
			DestroyMenu(popupmenu);
		}
	default:
		return(DefWindowProc(hWnd, message, wParam, lParam));
		break;
	}
	return(0l);
}

BOOL ColumnSelect_TreeView_GetCheckState(HWND hwndTreeView, HTREEITEM hItem)
{
    TVITEM tvItem;

    // Prepare to receive the desired information.
    tvItem.mask = TVIF_HANDLE | TVIF_STATE;
    tvItem.hItem = hItem;
    tvItem.stateMask = TVIS_STATEIMAGEMASK;

    // Request the information.
    TreeView_GetItem(hwndTreeView, &tvItem);

    // Return zero if it's not checked, or nonzero otherwise.
    return ((BOOL)(tvItem.state >> 12) -1);
}

LRESULT APIENTRY ColumnSelectDialog(HWND hDlg, unsigned message, WORD wParam, LONG lParam)
{
	HWND hwndTV;
	int i;
	char buf[30];
	//HTREEITEM selected, other;
	hwndTV = GetDlgItem(hDlg, IDC_COL_SEL_TREE);
	
	switch(message)
	{
	case WM_INITDIALOG:
		TranslateDialag(hDlg, "COL_SELECT");

    	SendDlgItemMessage(	hDlg, IDC_OPTION_ROMBROWSER, BM_SETCHECK,
	    	guioptions.display_romlist ? BST_CHECKED : BST_UNCHECKED, 0);
		SendDlgItemMessage(	hDlg, IDC_OPTION_ENABLE_BOXART, BM_SETCHECK,
			guioptions.display_boxart ? BST_CHECKED : BST_UNCHECKED, 0);

		sprintf(buf,"%d",guioptions.boxart_image_width);
		SetDlgItemText(hDlg,IDC_EDIT_BOXART_WIDTH, buf);
		sprintf(buf,"%d",guioptions.boxart_image_height);
		SetDlgItemText(hDlg,IDC_EDIT_BOXART_HEIGHT, buf);
		sprintf(buf,"%d",guioptions.boxart_image_x_spacing);
		SetDlgItemText(hDlg,IDC_EDIT_BOXART_X_SPACING, buf);
		sprintf(buf,"%d",guioptions.boxart_image_y_spacing);
		SetDlgItemText(hDlg,IDC_EDIT_BOXART_Y_SPACING, buf);

		switch(rlstatus.romlistNameToDisplay)
		{
		case ROMLIST_DISPLAY_ALTER_NAME:
			CheckRadioButton(hDlg, IDC_ALT_NAME, IDC_ROM_FILENAME, IDC_ALT_NAME);
			break;
		case ROMLIST_DISPLAY_INTERNAL_NAME:
			CheckRadioButton(hDlg, IDC_ALT_NAME, IDC_ROM_FILENAME, IDC_INTERNAL_NAME);
			break;
		case ROMLIST_DISPLAY_FILENAME:
			CheckRadioButton(hDlg, IDC_ALT_NAME, IDC_ROM_FILENAME, IDC_ROM_FILENAME);
			break;
		}

		{
			//Make sure the checkboxes can be displayed correctly, TreeView has some timing issue.
			LONG val = GetWindowLong(hwndTV, GWL_STYLE);
			val &= ~TVS_CHECKBOXES;
			SetWindowLong(hwndTV, GWL_STYLE, val);
			val |= TVS_CHECKBOXES;
			SetWindowLong(hwndTV, GWL_STYLE, val);
		}

		InsertColumnsIntoTreeView(hwndTV);

		return(TRUE);
		break;


    //Propertysheet handling
	case WM_NOTIFY:
		{
		LPNMHDR lpnm = (LPNMHDR) lParam;

        switch (lpnm->code)
            {
			case PSN_APPLY:
				SendMessage(hDlg, WM_COMMAND, IDOK, lParam);
                EndDialog(lpnm->hwndFrom, TRUE);
				break;

            case PSN_RESET :
                //Handle a Cancel button click, if necessary
                EndDialog(lpnm->hwndFrom, TRUE);
				break;
			}
		}
        return(TRUE);


	case WM_COMMAND:
		switch(wParam)
		{
		case IDOK:
			
            
            
			//Check the rom filename selecting
			if( IsDlgButtonChecked(hDlg, IDC_ALT_NAME) == BST_CHECKED )
			{
				rlstatus.romlistNameToDisplay = ROMLIST_DISPLAY_ALTER_NAME;
			}
			else if( IsDlgButtonChecked(hDlg, IDC_INTERNAL_NAME) == BST_CHECKED )
			{
				rlstatus.romlistNameToDisplay = ROMLIST_DISPLAY_INTERNAL_NAME;
			}
			else
			{
				rlstatus.romlistNameToDisplay = ROMLIST_DISPLAY_FILENAME;
			}
			
			for( i=1; i<numberOfRomListColumns; i++ )
			{
				romListColumns[i].enabled = ColumnSelect_TreeView_GetCheckState(hwndTV, romListColumns[i].treeViewID);
			}

			{
				int newval;
				GetDlgItemText(hDlg,IDC_EDIT_BOXART_WIDTH, buf, 29);
				newval = atoi(buf);
				if( newval >=16 && newval != guioptions.boxart_image_width && newval <= 1024 )
				{
					guioptions.boxart_image_width = newval;
					REGISTRY_WriteDWORD( "BoxartImageWidth", newval);
					EndDialog(hDlg, TRUE);
					SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
				}

				GetDlgItemText(hDlg,IDC_EDIT_BOXART_HEIGHT, buf, 29);
				newval = atoi(buf);
				if( newval >=12 && newval != guioptions.boxart_image_height && newval <= 720 )
				{
					guioptions.boxart_image_height = newval;
					REGISTRY_WriteDWORD( "BoxartImageHeight", newval);
					EndDialog(hDlg, TRUE);
					SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
				}

				GetDlgItemText(hDlg,IDC_EDIT_BOXART_X_SPACING, buf, 29);
				newval = atoi(buf);
				if( newval >=4 && newval != guioptions.boxart_image_x_spacing && newval <= 300 )
				{
					guioptions.boxart_image_x_spacing = newval;
					REGISTRY_WriteDWORD( "BoxartImageXSpacing", newval);
					EndDialog(hDlg, TRUE);
					SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
				}

				GetDlgItemText(hDlg,IDC_EDIT_BOXART_Y_SPACING, buf, 29);
				newval = atoi(buf);
				if( newval >=4 && newval != guioptions.boxart_image_y_spacing && newval <= 300 )
				{
					guioptions.boxart_image_y_spacing = newval;
					REGISTRY_WriteDWORD( "BoxartImageYSpacing", newval);
					EndDialog(hDlg, TRUE);
					SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
				}
			}

    	    if(	guioptions.display_romlist != ( SendDlgItemMessage( hDlg, IDC_OPTION_ROMBROWSER, BM_GETCHECK, 0, 0) == BST_CHECKED))
    	    {
    		    guioptions.display_romlist ^= 1;
    		    REGISTRY_WriteDWORD( "DisplayRomList", guioptions.display_romlist);
				EndDialog(hDlg, TRUE);
    		    SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
         	}

			if(	guioptions.display_boxart != ( SendDlgItemMessage( hDlg, IDC_OPTION_ENABLE_BOXART, BM_GETCHECK, 0, 0) == BST_CHECKED))
			{
				guioptions.display_boxart ^= 1;
				REGISTRY_WriteDWORD( "Displayboxart", guioptions.display_boxart);
				EndDialog(hDlg, TRUE);
				SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
			}

            if ( !emustatus.Emu_Is_Running)
			NewRomList_ListViewChangeWindowRect();

            
            EndDialog(hDlg, TRUE);

			//SendMessage(gui.hwnd1964main, WM_COMMAND, ID_FILE_FRESHROMLIST, 0);
			return(TRUE);
		case IDCANCEL:
			EndDialog(hDlg, TRUE);
			return(TRUE);
		}
		return(TRUE);
		break;
	}
	return(FALSE);
}


ColumnID GetColumnIDByName(char *name)
{
	int i;
	for( i=0; i<numberOfRomListColumns; i++ )
	{
		if( stricmp(TranslateStringByString(name), TranslateStringByString(romListColumns[i].text)) == 0 )
		{
			return (ColumnID)i;
		}
	}

	return (ColumnID)0;
}

ColumnID GetColumnIDByPos(int pos)
{
	int i;
	if( pos >= 0 && pos < numberOfRomListColumns )
	{
		for( i=0; i<numberOfRomListColumns; i++ )
		{
			if( romListColumns[i].colPos = pos )
			{
				return (ColumnID)i;
			}
		}

		return (ColumnID)(numberOfRomListColumns-1);
	}
	else
	{
		return (ColumnID)(numberOfRomListColumns-1);
	}
}

void InsertColumnsIntoTreeView(HWND hwndTV)
{
	TVINSERTSTRUCT insItem;
	int i;

	//Insert all items into the Tree View
	insItem.hParent = NULL;
	insItem.hInsertAfter = TVI_LAST;
	insItem.item.mask = TVIF_TEXT | TVIF_STATE;
	insItem.item.hItem = 0;
	insItem.item.cchTextMax = 10;
	insItem.item.cChildren = 0;
	insItem.item.iImage = 0;
	insItem.item.lParam = 0;
	insItem.item.stateMask = TVIS_STATEIMAGEMASK;
	
	for( i=1; i<numberOfRomListColumns; i++ )
	{
		insItem.item.state = INDEXTOSTATEIMAGEMASK((romListColumns[i].enabled ? 2 : 1));
		insItem.item.pszText = TranslateStringByString(romListColumns[i].text);
		romListColumns[i].treeViewID = TreeView_InsertItem(hwndTV, &insItem);
	}
}

BOOL LinkBoxArtImageByDialog(void)
{
	OPENFILENAME	ofn;
	char			szFileName[MAXFILENAME];
	char			szFileTitle[MAXFILENAME];
	char			szPath[_MAX_PATH];

	memset(&szFileName, 0, sizeof(szFileName));
	memset(&szFileTitle, 0, sizeof(szFileTitle));
	memset(szPath, 0, _MAX_PATH);


	strcpy(szPath, directories.boxart_directory_to_use);

	ofn.lStructSize = sizeof(OPENFILENAME);
	ofn.hwndOwner = gui.hwnd1964main;
	ofn.lpstrFilter = "JPEG Files (*.jpg)\0*.jpg\0GIF Files (*.gif)\0*.gif\0Bitmap Files (*.bmp)\0*.bmp\0\0";
	ofn.lpstrCustomFilter = NULL;
	ofn.nMaxCustFilter = 0;
	ofn.nFilterIndex = 1;
	ofn.lpstrFile = szFileName;
	ofn.nMaxFile = MAXFILENAME;
	ofn.lpstrInitialDir = szPath;
	ofn.lpstrFileTitle = szFileTitle;
	ofn.nMaxFileTitle = MAXFILENAME;
	ofn.lpstrTitle = "Link Box Art Image";
	ofn.lpstrDefExt = "";
	ofn.Flags = OFN_ENABLESIZING | OFN_HIDEREADONLY;

	if(GetSaveFileName((LPOPENFILENAME) & ofn))
	{
		strcpy(romlist[rlstatus.selected_rom_index]->pinientry->iconFilename, szFileName);
		FileIO_Write1964Ini();
		return TRUE;
	}
	else
	{
		return FALSE;
	}
}